Objetivos

completar…

Destinatarios

Completar….

El detalle procedimental utilizado en el presente documento, tiene como objetivo que pueda ser utilizado por quienes ya manejan programación en R, pero también por quienes se están iniciando por ese camino.

Procedimiento

A continuación, comenzamos a explicar el paso a paso para realizar la limpieza y organización de los datos, según los objetivos presentados.

Para comenzar, se deben realizar configuraciones iniciales, las cuales iremos detallando a continuación.

Incorporamos las librerias a utilizar.

library(tidyverse)      
#library(googlesheets4)  
library(gargle)         
library(funModeling)    
library(kableExtra)
library(plotly)
library(patchwork)#superponer graficos
library(RColorBrewer)

#library(tm)
#library(lubridate) 
#library(datos)
#library( hms)

Creamos objetos que vamos a utlizar en diversas oportunidades y solo debemos invocarlos.

azul <- "#344D7E"
verde <-  "#4A9FC7"
gris <- "#75838F"
rosa1 <- "#B95192"
rosa2 <- "#EE5777"
naranja <- "#FF764C"
amarillo <- "#FFA600"
gris <- "#75838F"
lila <- "#755395"
genero <- c("#8624F5", "#1FC3AA")


# Estilo limpio con líneas de referencia verticales en gris claro
estilov <- theme(panel.grid = element_blank(),
                 plot.background = element_rect(fill = "#FBFCFC"),
                 panel.background = element_blank(),
                 panel.grid.major.x = element_line(color = "#AEB6BF"),
                 text = element_text(family = "Roboto"))

# Estilo limpio con líneas de referencia horizontales en gris claro
estiloh <- theme(panel.grid = element_blank(),
                 plot.background = element_rect(fill = "#FBFCFC"),
                 panel.background = element_blank(),
                 panel.grid.major.y = element_line(color = "#AEB6BF"),
                 text = element_text(family = "Roboto"))


fuente <- "Fuente: Elaboración propia"

Incorporamos las bases de datos a utilizar.

original <- read.csv("Data.csv", stringsAsFactors = TRUE)

Almacenamos los datos en objeto para evitar usar la base original.

#rm(d1)
d1<- original

Demos un vistazo de lo que tenemos en el Dataframe:

#status(d1)

Comenzamos trabajando con los nombres de las columnas. Y consultamos los nombres de las mismas.

limpios <- make.names(colnames(d1))
colnames(d1) <- limpios

#names(d1)

Cambiamos los nombres de las columnas, para que sean en castellano y sean más facil de interpretar.

#rm(d1)

d1 <- d1%>% 
  rename(
  edad=  "ï..Age",
  rotacion= "Attrition",
  viaje_negocio="BusinessTravel",
  tasa_diaria="DailyRate", 
  departamento=Department,
  distancia=DistanceFromHome,
  educacion=Education,
  especialidad=EducationField,
  cuenta_empleado=EmployeeCount,
  dotacion=EmployeeNumber,
  clima=EnvironmentSatisfaction,
  genero=Gender,
  tasa_horaria=HourlyRate, 
  participacion=JobInvolvement,
  jerarquia=JobLevel,
  puesto=JobRole,
  satisfaccion=JobSatisfaction,
  est_civil=MaritalStatus,
  sueldo=MonthlyIncome,
  tasa_sueldo=MonthlyRate,
  companias_trabajadas=NumCompaniesWorked,
  mayor_18=Over18,
  hs_extras=OverTime,
  aumento_porcentual= PercentSalaryHike,
  desempeno=PerformanceRating, # no uso la ñ
  vinculo=RelationshipSatisfaction,
  horas=StandardHours,
  ESO= StockOptionLevel, # (Employee Stock Option),
  anios_trabajados=TotalWorkingYears,
  entrenamientos_ly=TrainingTimesLastYear, 
  bce_vida_trabajo= WorkLifeBalance,
  antiguedad=YearsAtCompany,
  antiguedad_puesto=YearsInCurrentRole,
  antiguedad_ult_promocion= YearsSinceLastPromotion,
  antiguedad_gte= YearsWithCurrManager
  )

Variables

Vamos a explorar los tipos de variables.

Volvemos a revisar nuestra base y verificamos que las variables no requieren una modificación del formato, en esta instancia.

#str(d1)

Primera observación a las variables numericas. Sin realizar mucho análisis, podemos conocer el estado de las variables númericas, para tener una referencia inicial, seleccionando las variables a trabajar.

Eliminamos las columnas que no vamos a usar en el análisis

d1<- d1 %>% 
  select(everything(),-cuenta_empleado,-horas,)
plot_num(d1)

Vamos a explorar las diferentes variables.

Rotacion

Edito las observaciones en ingles

d1<- d1 %>% 
 mutate(rotacion = fct_collapse(rotacion,"Si"= "Yes"))

Viaje de trabajo

Armo una escala para facilitar su interpretación.

# armo una escala

#no - poco - frecuente

d1<- d1 %>% 
 mutate(viaje_negocio = fct_collapse(viaje_negocio,"Poco"= "Travel_Rarely",
                                                     "Frecuente"="Travel_Frequently" ,
                                                     "No"="Non-Travel"  ))

1° Visualización

d1%>%
  select(viaje_negocio)%>%
  group_by(viaje_negocio)%>%
  mutate(cuenta = 1) %>% 
  rename("Viaje de Negocio"= "viaje_negocio")%>% 
  summarise(Cantidad = sum(cuenta)) %>% 
  arrange(-Cantidad)
## # A tibble: 3 x 2
##   `Viaje de Negocio` Cantidad
##   <fct>                 <dbl>
## 1 Poco                   1043
## 2 Frecuente               277
## 3 No                      150

2° Visualización

d1%>%
  select(viaje_negocio)%>%
  group_by(viaje_negocio)%>%
  mutate(cuenta = 1) %>% 
  rename("Viaje de Negocio"= "viaje_negocio")%>% 
  summarise(Cantidad = sum(cuenta)) %>% 
  arrange(-Cantidad)%>%
  kable("html", escape=F) %>% 
  kable_styling(full_width = TRUE, bootstrap_options = c("striped","hover","condensed" )) %>% 
  row_spec(0, bold=T, color="white", background = azul) %>% 
  footnote(general = fuente)
Viaje de Negocio Cantidad
Poco 1043
Frecuente 277
No 150
Note:
Fuente: Elaboración propia

Departamento

Simplifico los nombres.

d1<- d1 %>% 
 mutate(departamento = fct_collapse(departamento,  "R&D"="Research & Development" , 
                                                   "HR"="Human Resources",
                                                    "Ventas"= "Sales"))


d1%>%
  select(departamento)%>%
  group_by(departamento)%>%
  mutate(cuenta = 1) %>% 
  summarise(Cuenta = sum(cuenta)) %>% 
  arrange(-Cuenta)%>%
  kable("html", escape=F) %>% 
  kable_styling(full_width = TRUE, bootstrap_options = c("striped","hover","condensed" )) %>% 
  row_spec(0, bold=T, color="white", background = azul) %>% 
  footnote(general = fuente)
departamento Cuenta
R&D 961
Ventas 446
HR 63
Note:
Fuente: Elaboración propia

Género

d1<- d1 %>% 
 mutate(genero = fct_collapse(genero,  "Femenino"="Female" , 
                                                   "Masculino"="Male",
                                                    ))

d1%>%
  select(genero)%>%
  group_by(genero)%>%
  mutate(cuenta = 1) %>% 
  summarise(Cuenta = sum(cuenta)) %>% 
  arrange(-Cuenta)%>%
  kable("html", escape=F) %>% 
  kable_styling(full_width = TRUE, bootstrap_options = c("striped","hover","condensed" )) %>% 
  row_spec(0, bold=T, color="white", background = azul) %>% 
  footnote(general = fuente)
genero Cuenta
Masculino 882
Femenino 588
Note:
Fuente: Elaboración propia
div <- d1 %>% 
select(genero) %>% 
  mutate(genero = factor(genero, 
                         levels = c("Femenino", "Masculino"))) %>% 
  group_by(genero) %>% 
  summarise (n = n()) %>% 
  mutate(freq = n/sum(n)) %>% 
  arrange(-n)

# Compute the cumulative percentages (top of each rectangle)
div$ymax <- cumsum(div$freq)

# Compute the bottom of each rectangle
div$ymin <- c(0, head(div$ymax, n=-1))

# Compute label position
div$labelPosition <- (div$ymax + div$ymin) / 2

# Compute a good label
div$label <- paste0(div$genero, "\n Cant: ", div$n)

# Make the plot
ggplot(div, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=genero)) +
  geom_rect() +
  coord_polar(theta="y") + # Try to remove that to understand how the chart is built initially
  xlim(c(2, 4)) +# Try to remove that to see how to make a pie chart
  scale_fill_manual(values = c("#8624F5",  "#1FC3AA", "#FFD129","#75838F")) +
  theme_void() +
  theme(legend.position = "right",
        panel.background = element_blank(),
        text = element_text(family = "Roboto")) +
  labs(title = "Género",
       fill = "Género", 
       caption = fuente)

Puesto

d1<- d1 %>% 
 mutate(puesto = fct_collapse(puesto,  "Vendedor"="Sales Executive" , 
                                        "Investigador"="Research Scientist",
                                        "Tec_laboratorio"="Laboratory Technician",
                                        "Dir_Operativo"="Manufacturing Director",
                                        "Atencion_cliente"="Healthcare Representative",
                                        "Gerente"="Manedadr",
                                        "Comercial"="Sales Representative",
                                        "Director"="Research Director",
                                        "HR"="Human Resources"))

d1%>%
  select(puesto)%>%
  group_by(puesto)%>%
  mutate(cuenta = 1) %>% 
  summarise(Cuenta = sum(cuenta)) %>% 
  arrange(-Cuenta)%>%
  kable("html", escape=F) %>% 
  kable_styling(full_width = TRUE, bootstrap_options = c("striped","hover","condensed" )) %>% 
  row_spec(0, bold=T, color="white", background = azul) %>% 
  footnote(general = fuente)
puesto Cuenta
Vendedor 326
Investigador 292
Tec_laboratorio 259
Dir_Operativo 145
Atencion_cliente 131
Manager 102
Comercial 83
Director 80
HR 52
Note:
Fuente: Elaboración propia

Estado civil

d1<- d1 %>% 
 mutate(est_civil = fct_collapse(est_civil,  "Casadx"="Married" , 
                                                   "Solterx"="Single",
                                                    "Divorciadx"= "Divorced"))

d1%>%
  select(est_civil)%>%
  group_by(est_civil)%>%
  mutate(cuenta = 1) %>% 
  summarise(Cuenta = sum(cuenta)) %>% 
  arrange(-Cuenta)%>%
  kable("html", escape=F) %>% 
  kable_styling(full_width = TRUE, bootstrap_options = c("striped","hover","condensed" )) %>% 
  row_spec(0, bold=T, color="white", background = azul) %>% 
  footnote(general = fuente)
est_civil Cuenta
Casadx 673
Solterx 470
Divorciadx 327
Note:
Fuente: Elaboración propia

Edad

Armamos grupos de edad

Primero consultamos las edades para armar las categorías:

d1%>%
  select(edad)%>%
  group_by(edad)%>%
  mutate(cuenta = 1) %>% 
  summarise(Cuenta = sum(cuenta)) %>% 
  arrange(-Cuenta)
## # A tibble: 43 x 2
##     edad Cuenta
##    <int>  <dbl>
##  1    35     78
##  2    34     77
##  3    31     69
##  4    36     69
##  5    29     68
##  6    32     61
##  7    30     60
##  8    33     58
##  9    38     58
## 10    40     57
## # ... with 33 more rows

En función de las cantidades previas, armamos las categorías adecuadas:

d1<-d1%>% 
         mutate(edad_cat = case_when(
                                edad > 17 & edad <= 25 ~ "18-25",
                                edad > 25 & edad <= 35 ~ "26-35",
                                edad > 35 & edad <= 46 ~ "36-45",
                                edad > 45 & edad <= 50 ~ "46-50",
                                edad > 50 & edad <= 64 ~ "51-64",        
                                edad > 64             ~ "> 64"
                                )) %>% 
         mutate(edad_cat = factor(edad_cat,
         level = c("18-25","26-35", "36-45","46-50","51-64","> 64")
    )) 


d1%>%
  select(edad_cat)%>%
  group_by(edad_cat)%>%
  mutate(cuenta = 1) %>% 
  summarise(Cuenta = sum(cuenta)) %>% 
  arrange(-Cuenta)%>%
  kable("html", escape=F) %>% 
  kable_styling(full_width = TRUE, bootstrap_options = c("striped","hover","condensed" )) %>% 
  row_spec(0, bold=T, color="white", background = azul) %>% 
  footnote(general = fuente)
edad_cat Cuenta
26-35 606
36-45 501
51-64 143
18-25 123
46-50 97
Note:
Fuente: Elaboración propia

Especialidad

d1%>%
  select(especialidad)%>%
  group_by(especialidad)%>%
  mutate(cuenta = 1) %>% 
  summarise(Cuenta = sum(cuenta)) %>% 
  arrange(-Cuenta)
## # A tibble: 6 x 2
##   especialidad     Cuenta
##   <fct>             <dbl>
## 1 Life Sciences       606
## 2 Medical             464
## 3 Marketing           159
## 4 Technical Degree    132
## 5 Other                82
## 6 Human Resources      27
d1<- d1 %>% 
 mutate(especialidad = fct_collapse(especialidad,  "Ciencias"="Life Sciences" , 
                                                   "Medicina"="Medical",                                                                                       "Mkt"="Marketing",                                                                                          "HR"="Human Resources",
                                                   "Otros"="Other"
                                                    ))

Relaciones

Empecemos viendo la representación porcentual de rotación.

Podemos visualizarlo en una tabla:

d1%>%
  select(rotacion)%>%
  group_by(rotacion)%>%
  rename("Rotación"="rotacion") %>% 
  mutate(cuenta = 1) %>% 
  summarise(Cantidad = sum(cuenta)) %>% 
  arrange(-Cantidad) %>% 
  mutate(Porcentaje = round(prop.table(Cantidad), 2)) %>% 
  kable("html", escape=F) %>% 
  kable_styling(full_width = TRUE, bootstrap_options = c("striped","hover","condensed" )) %>% 
  row_spec(0, bold=T, color="white", background = azul) %>% 
  footnote(general = fuente)
Rotación Cantidad Porcentaje
No 1233 0.84
Si 237 0.16
Note:
Fuente: Elaboración propia

En un pie chart, ya sea incluyendo cantidades o solo una referencia visual:

g7<-d1%>% 
  select(rotacion)%>%
  group_by(rotacion)%>%
  summarise(counts = n()) %>%
  mutate(prop = (counts / sum(counts)) * 100) %>%
  arrange(desc(prop)) %>% 
ggplot(aes("", counts)) +
  geom_col(
    position = "fill",
    color = "black",
    width = 1,
    aes(fill = factor(rotacion))
  ) +
  geom_text(
    aes(label = str_c(round(prop), "%"), group = factor(rotacion)),
    position = position_fill(vjust = 0.5),
    color = "white",
    size = 6,
    show.legend = FALSE,
    fontface = "bold"
  ) +
  coord_polar(theta = "y") +
  theme_void() +
  scale_fill_manual (values = c(azul,verde)) +
  theme_void() +
  labs(
    title = "Rotación ",
    subtitle = "",
    caption = "",
    fill = ""
  )
g8<-d1%>% 
  select(rotacion)%>%
  group_by(rotacion)%>%
  summarise(counts = n()) %>%
  mutate(prop = (counts / sum(counts)) * 100) %>%
  arrange(desc(prop))

g8<-ggplot(g8, aes(x="", y=prop, fill=rotacion)) +
  geom_bar(stat="identity", width=1, color="white") +
  coord_polar("y", start=0) +
  theme_void() + 
  theme(legend.position="none") +
  geom_text(aes(label = rotacion), color = "white", size=6)+
  scale_fill_brewer(palette="Set2")
g7

g8

Especialidad & Rotación

Ahora relacionemos la especialidad con la rotación.

d1%>% 
  rename(
  Especialidad=  "especialidad")%>%
  plot_ly(x = ~Especialidad, color  =~rotacion, colors = "Accent" )%>%
  layout(yaxis = list(title = 'Cantidad'))

Genero & Especialidad

De los que se fueron, podemos observar la relación entre género y campo de especialidad

g1<-
  d1 %>% 
    select(rotacion,genero,especialidad) %>%
    rename("Género"=genero) %>% 
    filter (rotacion=="Si") %>%
    group_by(especialidad,Género) %>% 
    summarise(Cantidad=n()) 

  ggplot(data=g1,aes(x=especialidad,y = Cantidad ,fill=Género))+
    geom_bar(stat="identity", position=position_dodge())+
  scale_fill_manual(values = c(azul, verde)) +
    ggtitle("Especialidad & Genero ")+
  labs(x = "", y = "")

Ingresos vs Rotación

Veamos la relación entre ingresos y rotación.

Mediante la siguiente tabla analizamos los valores estandar.

d1%>% 
  summarise(Mediana = median(sueldo), 
              Promedio = mean(sueldo),
              Max = max(sueldo), 
              Min = min(sueldo)) %>% 
  kable("html", escape=F) %>% 
  kable_styling(full_width = TRUE, bootstrap_options = c("striped","hover","condensed" )) %>% 
  row_spec(0, bold=T, color="white", background = azul)
Mediana Promedio Max Min
4919 6502.931 19999 1009

Nos interesa relacionar genero, ingresos y rotacion.

Como vemos en el siguiente grafico, quienes se fueron de la empresa, es similar el sueldo, al igual que la cantidad de personas. La mayoria de los outliers se presenta en el género masculino.

De los que se encuentran activos, los sueldos más altos los tienen las mujeres.

ggplot(d1, aes(x=rotacion, y=sueldo, color=genero, fill=genero)) +
    geom_boxplot()

g2<-d1%>% 
  filter(rotacion=="Si")%>%
  plot_ly(x = ~departamento, color  =~genero, colors = "Accent" )%>%
  layout(yaxis = list(title = 'Cantidad'))

g3<-d1%>% 
  filter(rotacion=="No")%>%
  plot_ly(x = ~departamento, color  =~genero, colors = "Accent" )%>%
  layout(yaxis = list(title = 'Cantidad'))

g2
g3

¿Hay alguna relacion entre las personas que se fueron y los que hicieron horas extras?

Primero veamos un cuadro general entre Genero, horas extras y sueldo.

Vemos que las mujeres con sueldo mas alto, son quienes hacen horas extras, en cambio entre los hombres, hagan o no horas extras el sueldo es similar.

g6<-ggplot(d1, aes(x=hs_extras, y=sueldo, color=genero, fill=genero)) +
    geom_boxplot()

g6

Veamos ahora como impacta las horas extras extre las personas que se van de la compañia:

g4<-d1 %>% 
  select(hs_extras, sueldo, genero, rotacion) %>% 
  filter(rotacion=="Si") %>% 
  ggplot( aes(x=hs_extras, y=sueldo, color=genero, fill=genero)) +
    geom_boxplot()+
    labs(title='Bajas')


g5<-d1 %>% 
  select(hs_extras, sueldo, genero, rotacion) %>% 
  filter(rotacion=="No") %>% 
  ggplot( aes(x=hs_extras, y=sueldo, color=genero, fill=genero)) +
    geom_boxplot()+
   labs(title='Activos')

g4

g5

Podemos observar que los sueldos promedio de quienes se van de la compañia no tienen diferencias por genero.

 d1 %>% 
  select(puesto, sueldo, genero,rotacion) %>% 
  filter(rotacion=="Si") %>% 
  group_by(genero) %>% 
  summarise(media_salarial = mean(sueldo)) %>% 
  kable("html", escape=F) %>% 
  kable_styling(full_width = TRUE, bootstrap_options = c("striped","hover","condensed" )) %>% 
  row_spec(0, bold=T, color="white", background = azul) %>% 
  footnote(general = fuente)
genero media_salarial
Femenino 4769.736
Masculino 4797.160
Note:
Fuente: Elaboración propia
## Solo se reproduce en el dashboard 
#brecha <- d1 %>% 
#  select(puesto, sueldo, genero,rotacion) %>% 
#  filter(rotacion=="Si") %>% 
#  group_by(genero) %>% 
#  summarise(media_salarial = mean(sueldo))

#brecha_graf <- brecha %>% 
#  pivot_wider(., names_from = genero, values_from = media_salarial) %>% 
#  mutate(brecha = percent((Masculino-Femenino)/Masculino, 1),
#         x = (Masculino + Femenino)/2,
#         gap = Femenino/Masculino)

# Calcular el indicador de brecha salarial 
#brecha_promedio <- round(mean(brecha_graf$gap*100))

### Sueldo Promedio Mujeres

#(round(mean(brecha_graf$Femenino)), icon = "fa-female", color = "#8624F5")

### Sueldo Promedio Hombres
#valueBox(round(mean(brecha_graf$Masculino)), icon = "fa-male", color = "#1FC3AA")

Y si bien, los sueldos promedios son casi identicos, observamos que la cantidad de personas no activas de cada genero varia en forma considerable.

d1 %>% 
    select(rotacion,genero) %>%
    filter (rotacion=="Si") %>%
    group_by(genero) %>% 
    summarise(Cantidad=n()) 
## # A tibble: 2 x 2
##   genero    Cantidad
##   <fct>        <int>
## 1 Femenino        87
## 2 Masculino      150

Podemos observar la misma información con la siguiente visualización

d1%>% 
  filter(rotacion=="Si") %>% 
  rename( Género=  "genero")%>%
  plot_ly(x = ~Género, color  =~rotacion, colors = "Accent" )%>%
  layout(yaxis = list(title = 'Cantidad'))
LS0tDQp0aXRsZTogIkluZm9ybWUgRGFzaGJvYXJkIg0Kc3VidGl0bGU6ICIqSW5mb3JtZSoiDQphdXRob3I6ICIqKllhbmVsIFBhdWxldHRlKioiDQpkYXRlOiAnQcOxbyAyMDIyJw0KbGlua2NvbG9yOiBibHVlDQp1cmxjb2xvcjogYmx1ZQ0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRoZW1lOiBzcGFjZWxhYg0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkgDQoNCmBgYA0KDQoNCiMjIE9iamV0aXZvcw0KDQpjb21wbGV0YXIuLi4gDQoNCg0KDQojIyBEZXN0aW5hdGFyaW9zDQoNCg0KQ29tcGxldGFyLi4uLg0KDQpFbCBkZXRhbGxlIHByb2NlZGltZW50YWwgdXRpbGl6YWRvIGVuIGVsIHByZXNlbnRlIGRvY3VtZW50bywgdGllbmUgY29tbyBvYmpldGl2byBxdWUgcHVlZGEgc2VyIHV0aWxpemFkbyBwb3IgcXVpZW5lcyB5YSBtYW5lamFuIHByb2dyYW1hY2nDs24gZW4gUiwgcGVybyB0YW1iacOpbiAgcG9yIHF1aWVuZXMgc2UgZXN0w6FuIGluaWNpYW5kbyBwb3IgZXNlIGNhbWluby4gDQoNCg0KIyMgUHJvY2VkaW1pZW50bw0KDQpBIGNvbnRpbnVhY2nDs24sIGNvbWVuemFtb3MgYSBleHBsaWNhciBlbCBwYXNvIGEgcGFzbyAgcGFyYSByZWFsaXphciBsYSBsaW1waWV6YSB5IG9yZ2FuaXphY2nDs24gZGUgbG9zIGRhdG9zLCBzZWfDum4gbG9zIG9iamV0aXZvcyBwcmVzZW50YWRvcy4gDQoNClBhcmEgY29tZW56YXIsIHNlIGRlYmVuIHJlYWxpemFyIGNvbmZpZ3VyYWNpb25lcyBpbmljaWFsZXMsIGxhcyBjdWFsZXMgaXJlbW9zIGRldGFsbGFuZG8gYSBjb250aW51YWNpw7NuLiANCg0KSW5jb3Jwb3JhbW9zIGxhcyBsaWJyZXJpYXMgYSB1dGlsaXphci4NCg0KYGBge3IgfQ0KDQpsaWJyYXJ5KHRpZHl2ZXJzZSkgICAgICANCiNsaWJyYXJ5KGdvb2dsZXNoZWV0czQpICANCmxpYnJhcnkoZ2FyZ2xlKSAgICAgICAgIA0KbGlicmFyeShmdW5Nb2RlbGluZykgICAgDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkocGF0Y2h3b3JrKSNzdXBlcnBvbmVyIGdyYWZpY29zDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCg0KI2xpYnJhcnkodG0pDQojbGlicmFyeShsdWJyaWRhdGUpIA0KI2xpYnJhcnkoZGF0b3MpDQojbGlicmFyeSggaG1zKQ0KYGBgDQoNCkNyZWFtb3Mgb2JqZXRvcyBxdWUgdmFtb3MgYSB1dGxpemFyIGVuIGRpdmVyc2FzIG9wb3J0dW5pZGFkZXMgeSBzb2xvIGRlYmVtb3MgaW52b2Nhcmxvcy4NCg0KYGBge3IgfQ0KDQphenVsIDwtICIjMzQ0RDdFIg0KdmVyZGUgPC0gICIjNEE5RkM3Ig0KZ3JpcyA8LSAiIzc1ODM4RiINCnJvc2ExIDwtICIjQjk1MTkyIg0Kcm9zYTIgPC0gIiNFRTU3NzciDQpuYXJhbmphIDwtICIjRkY3NjRDIg0KYW1hcmlsbG8gPC0gIiNGRkE2MDAiDQpncmlzIDwtICIjNzU4MzhGIg0KbGlsYSA8LSAiIzc1NTM5NSINCmdlbmVybyA8LSBjKCIjODYyNEY1IiwgIiMxRkMzQUEiKQ0KDQoNCiMgRXN0aWxvIGxpbXBpbyBjb24gbMOtbmVhcyBkZSByZWZlcmVuY2lhIHZlcnRpY2FsZXMgZW4gZ3JpcyBjbGFybw0KZXN0aWxvdiA8LSB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRkJGQ0ZDIiksDQogICAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZShjb2xvciA9ICIjQUVCNkJGIiksDQogICAgICAgICAgICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIlJvYm90byIpKQ0KDQojIEVzdGlsbyBsaW1waW8gY29uIGzDrW5lYXMgZGUgcmVmZXJlbmNpYSBob3Jpem9udGFsZXMgZW4gZ3JpcyBjbGFybw0KZXN0aWxvaCA8LSB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRkJGQ0ZDIiksDQogICAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICIjQUVCNkJGIiksDQogICAgICAgICAgICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIlJvYm90byIpKQ0KDQoNCmZ1ZW50ZSA8LSAiRnVlbnRlOiBFbGFib3JhY2nDs24gcHJvcGlhIg0KYGBgDQoNCg0KSW5jb3Jwb3JhbW9zIGxhcyBiYXNlcyBkZSBkYXRvcyBhIHV0aWxpemFyLg0KDQpgYGB7cn0NCm9yaWdpbmFsIDwtIHJlYWQuY3N2KCJEYXRhLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBUUlVFKQ0KDQpgYGANCg0KDQpBbG1hY2VuYW1vcyBsb3MgZGF0b3MgZW4gIG9iamV0byBwYXJhIGV2aXRhciB1c2FyIGxhIGJhc2Ugb3JpZ2luYWwuDQoNCmBgYHtyfQ0KI3JtKGQxKQ0KZDE8LSBvcmlnaW5hbA0KDQpgYGANCg0KDQpEZW1vcyB1biB2aXN0YXpvIGRlIGxvIHF1ZSB0ZW5lbW9zIGVuIGVsIERhdGFmcmFtZToNCg0KDQpgYGB7cn0NCiNzdGF0dXMoZDEpDQoNCmBgYA0KDQpDb21lbnphbW9zIHRyYWJhamFuZG8gY29uIGxvcyBub21icmVzIGRlIGxhcyBjb2x1bW5hcy4gWSBjb25zdWx0YW1vcyBsb3Mgbm9tYnJlcyBkZSBsYXMgbWlzbWFzLiANCg0KDQpgYGB7cn0NCg0KbGltcGlvcyA8LSBtYWtlLm5hbWVzKGNvbG5hbWVzKGQxKSkNCmNvbG5hbWVzKGQxKSA8LSBsaW1waW9zDQoNCiNuYW1lcyhkMSkNCg0KYGBgDQoNCkNhbWJpYW1vcyBsb3Mgbm9tYnJlcyBkZSBsYXMgY29sdW1uYXMsIHBhcmEgcXVlIHNlYW4gZW4gY2FzdGVsbGFubyB5IHNlYW4gbcOhcyBmYWNpbCBkZSBpbnRlcnByZXRhci4NCg0KYGBge3J9DQojcm0oZDEpDQoNCmQxIDwtIGQxJT4lIA0KICByZW5hbWUoDQogIGVkYWQ9ICAiw68uLkFnZSIsDQogIHJvdGFjaW9uPSAiQXR0cml0aW9uIiwNCiAgdmlhamVfbmVnb2Npbz0iQnVzaW5lc3NUcmF2ZWwiLA0KICB0YXNhX2RpYXJpYT0iRGFpbHlSYXRlIiwgDQogIGRlcGFydGFtZW50bz1EZXBhcnRtZW50LA0KICBkaXN0YW5jaWE9RGlzdGFuY2VGcm9tSG9tZSwNCiAgZWR1Y2FjaW9uPUVkdWNhdGlvbiwNCiAgZXNwZWNpYWxpZGFkPUVkdWNhdGlvbkZpZWxkLA0KICBjdWVudGFfZW1wbGVhZG89RW1wbG95ZWVDb3VudCwNCiAgZG90YWNpb249RW1wbG95ZWVOdW1iZXIsDQogIGNsaW1hPUVudmlyb25tZW50U2F0aXNmYWN0aW9uLA0KICBnZW5lcm89R2VuZGVyLA0KICB0YXNhX2hvcmFyaWE9SG91cmx5UmF0ZSwgDQogIHBhcnRpY2lwYWNpb249Sm9iSW52b2x2ZW1lbnQsDQogIGplcmFycXVpYT1Kb2JMZXZlbCwNCiAgcHVlc3RvPUpvYlJvbGUsDQogIHNhdGlzZmFjY2lvbj1Kb2JTYXRpc2ZhY3Rpb24sDQogIGVzdF9jaXZpbD1NYXJpdGFsU3RhdHVzLA0KICBzdWVsZG89TW9udGhseUluY29tZSwNCiAgdGFzYV9zdWVsZG89TW9udGhseVJhdGUsDQogIGNvbXBhbmlhc190cmFiYWphZGFzPU51bUNvbXBhbmllc1dvcmtlZCwNCiAgbWF5b3JfMTg9T3ZlcjE4LA0KICBoc19leHRyYXM9T3ZlclRpbWUsDQogIGF1bWVudG9fcG9yY2VudHVhbD0gUGVyY2VudFNhbGFyeUhpa2UsDQogIGRlc2VtcGVubz1QZXJmb3JtYW5jZVJhdGluZywgIyBubyB1c28gbGEgw7ENCiAgdmluY3Vsbz1SZWxhdGlvbnNoaXBTYXRpc2ZhY3Rpb24sDQogIGhvcmFzPVN0YW5kYXJkSG91cnMsDQogIEVTTz0gU3RvY2tPcHRpb25MZXZlbCwgIyAoRW1wbG95ZWUgU3RvY2sgT3B0aW9uKSwNCiAgYW5pb3NfdHJhYmFqYWRvcz1Ub3RhbFdvcmtpbmdZZWFycywNCiAgZW50cmVuYW1pZW50b3NfbHk9VHJhaW5pbmdUaW1lc0xhc3RZZWFyLCANCiAgYmNlX3ZpZGFfdHJhYmFqbz0gV29ya0xpZmVCYWxhbmNlLA0KICBhbnRpZ3VlZGFkPVllYXJzQXRDb21wYW55LA0KICBhbnRpZ3VlZGFkX3B1ZXN0bz1ZZWFyc0luQ3VycmVudFJvbGUsDQogIGFudGlndWVkYWRfdWx0X3Byb21vY2lvbj0gWWVhcnNTaW5jZUxhc3RQcm9tb3Rpb24sDQogIGFudGlndWVkYWRfZ3RlPSBZZWFyc1dpdGhDdXJyTWFuYWdlcg0KICApDQpgYGANCg0KDQojIyBWYXJpYWJsZXMNCg0KVmFtb3MgIGEgZXhwbG9yYXIgbG9zIHRpcG9zIGRlIHZhcmlhYmxlcy4NCg0KVm9sdmVtb3MgYSByZXZpc2FyIG51ZXN0cmEgYmFzZSB5IHZlcmlmaWNhbW9zIHF1ZSBsYXMgdmFyaWFibGVzIG5vIHJlcXVpZXJlbiB1bmEgbW9kaWZpY2FjacOzbiBkZWwgZm9ybWF0bywgZW4gZXN0YSBpbnN0YW5jaWEuIA0KDQpgYGB7ciB9DQojc3RyKGQxKQ0KYGBgDQoNClByaW1lcmEgb2JzZXJ2YWNpw7NuIGEgbGFzIHZhcmlhYmxlcyBudW1lcmljYXMuDQpTaW4gcmVhbGl6YXIgbXVjaG8gYW7DoWxpc2lzLCBwb2RlbW9zIGNvbm9jZXIgZWwgZXN0YWRvIGRlIGxhcyB2YXJpYWJsZXMgbsO6bWVyaWNhcywgcGFyYSB0ZW5lciB1bmEgcmVmZXJlbmNpYSBpbmljaWFsLCBzZWxlY2Npb25hbmRvIGxhcyB2YXJpYWJsZXMgYSB0cmFiYWphci4gDQoNCg0KRWxpbWluYW1vcyBsYXMgY29sdW1uYXMgcXVlIG5vIHZhbW9zIGEgdXNhciBlbiBlbCBhbsOhbGlzaXMNCg0KYGBge3J9DQoNCmQxPC0gZDEgJT4lIA0KICBzZWxlY3QoZXZlcnl0aGluZygpLC1jdWVudGFfZW1wbGVhZG8sLWhvcmFzLCkNCg0KYGBgDQoNCmBgYHtyfQ0KDQpwbG90X251bShkMSkNCg0KYGBgDQoNCg0KVmFtb3MgYSBleHBsb3JhciAgbGFzIGRpZmVyZW50ZXMgdmFyaWFibGVzLg0KDQoNCg0KIyMjIFJvdGFjaW9uDQoNCkVkaXRvIGxhcyBvYnNlcnZhY2lvbmVzIGVuIGluZ2xlcw0KDQpgYGB7cn0NCg0KDQpkMTwtIGQxICU+JSANCiBtdXRhdGUocm90YWNpb24gPSBmY3RfY29sbGFwc2Uocm90YWNpb24sIlNpIj0gIlllcyIpKQ0KDQoNCmBgYA0KDQoNCiMjIyBWaWFqZSBkZSB0cmFiYWpvDQoNCg0KQXJtbyB1bmEgZXNjYWxhIHBhcmEgZmFjaWxpdGFyIHN1IGludGVycHJldGFjacOzbi4NCg0KYGBge3J9DQoNCiMgYXJtbyB1bmEgZXNjYWxhDQoNCiNubyAtIHBvY28gLSBmcmVjdWVudGUNCg0KZDE8LSBkMSAlPiUgDQogbXV0YXRlKHZpYWplX25lZ29jaW8gPSBmY3RfY29sbGFwc2UodmlhamVfbmVnb2NpbywiUG9jbyI9ICJUcmF2ZWxfUmFyZWx5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZyZWN1ZW50ZSI9IlRyYXZlbF9GcmVxdWVudGx5IiAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJObyI9Ik5vbi1UcmF2ZWwiICApKQ0KDQoNCmBgYA0KMcKwIFZpc3VhbGl6YWNpw7NuDQoNCmBgYHtyfQ0KZDElPiUNCiAgc2VsZWN0KHZpYWplX25lZ29jaW8pJT4lDQogIGdyb3VwX2J5KHZpYWplX25lZ29jaW8pJT4lDQogIG11dGF0ZShjdWVudGEgPSAxKSAlPiUgDQogIHJlbmFtZSgiVmlhamUgZGUgTmVnb2NpbyI9ICJ2aWFqZV9uZWdvY2lvIiklPiUgDQogIHN1bW1hcmlzZShDYW50aWRhZCA9IHN1bShjdWVudGEpKSAlPiUgDQogIGFycmFuZ2UoLUNhbnRpZGFkKQ0KDQpgYGANCg0KDQoywrAgVmlzdWFsaXphY2nDs24NCg0KYGBge3J9DQpkMSU+JQ0KICBzZWxlY3QodmlhamVfbmVnb2NpbyklPiUNCiAgZ3JvdXBfYnkodmlhamVfbmVnb2NpbyklPiUNCiAgbXV0YXRlKGN1ZW50YSA9IDEpICU+JSANCiAgcmVuYW1lKCJWaWFqZSBkZSBOZWdvY2lvIj0gInZpYWplX25lZ29jaW8iKSU+JSANCiAgc3VtbWFyaXNlKENhbnRpZGFkID0gc3VtKGN1ZW50YSkpICU+JSANCiAgYXJyYW5nZSgtQ2FudGlkYWQpJT4lDQogIGthYmxlKCJodG1sIiwgZXNjYXBlPUYpICU+JSANCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gVFJVRSwgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwiaG92ZXIiLCJjb25kZW5zZWQiICkpICU+JSANCiAgcm93X3NwZWMoMCwgYm9sZD1ULCBjb2xvcj0id2hpdGUiLCBiYWNrZ3JvdW5kID0gYXp1bCkgJT4lIA0KICBmb290bm90ZShnZW5lcmFsID0gZnVlbnRlKQ0KDQpgYGANCg0KDQoNCiMjIyBEZXBhcnRhbWVudG8NCg0KU2ltcGxpZmljbyBsb3Mgbm9tYnJlcy4NCg0KDQpgYGB7cn0NCg0KZDE8LSBkMSAlPiUgDQogbXV0YXRlKGRlcGFydGFtZW50byA9IGZjdF9jb2xsYXBzZShkZXBhcnRhbWVudG8sICAiUiZEIj0iUmVzZWFyY2ggJiBEZXZlbG9wbWVudCIgLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJIUiI9Ikh1bWFuIFJlc291cmNlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlZlbnRhcyI9ICJTYWxlcyIpKQ0KDQoNCmQxJT4lDQogIHNlbGVjdChkZXBhcnRhbWVudG8pJT4lDQogIGdyb3VwX2J5KGRlcGFydGFtZW50byklPiUNCiAgbXV0YXRlKGN1ZW50YSA9IDEpICU+JSANCiAgc3VtbWFyaXNlKEN1ZW50YSA9IHN1bShjdWVudGEpKSAlPiUgDQogIGFycmFuZ2UoLUN1ZW50YSklPiUNCiAga2FibGUoImh0bWwiLCBlc2NhcGU9RikgJT4lIA0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBUUlVFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCJob3ZlciIsImNvbmRlbnNlZCIgKSkgJT4lIA0KICByb3dfc3BlYygwLCBib2xkPVQsIGNvbG9yPSJ3aGl0ZSIsIGJhY2tncm91bmQgPSBhenVsKSAlPiUgDQogIGZvb3Rub3RlKGdlbmVyYWwgPSBmdWVudGUpDQpgYGANCg0KIyMjIEfDqW5lcm8NCg0KYGBge3J9DQoNCmQxPC0gZDEgJT4lIA0KIG11dGF0ZShnZW5lcm8gPSBmY3RfY29sbGFwc2UoZ2VuZXJvLCAgIkZlbWVuaW5vIj0iRmVtYWxlIiAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1hc2N1bGlubyI9Ik1hbGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpDQoNCmQxJT4lDQogIHNlbGVjdChnZW5lcm8pJT4lDQogIGdyb3VwX2J5KGdlbmVybyklPiUNCiAgbXV0YXRlKGN1ZW50YSA9IDEpICU+JSANCiAgc3VtbWFyaXNlKEN1ZW50YSA9IHN1bShjdWVudGEpKSAlPiUgDQogIGFycmFuZ2UoLUN1ZW50YSklPiUNCiAga2FibGUoImh0bWwiLCBlc2NhcGU9RikgJT4lIA0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBUUlVFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCJob3ZlciIsImNvbmRlbnNlZCIgKSkgJT4lIA0KICByb3dfc3BlYygwLCBib2xkPVQsIGNvbG9yPSJ3aGl0ZSIsIGJhY2tncm91bmQgPSBhenVsKSAlPiUgDQogIGZvb3Rub3RlKGdlbmVyYWwgPSBmdWVudGUpDQpgYGANCg0KYGBge3J9DQpkaXYgPC0gZDEgJT4lIA0Kc2VsZWN0KGdlbmVybykgJT4lIA0KICBtdXRhdGUoZ2VuZXJvID0gZmFjdG9yKGdlbmVybywgDQogICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiRmVtZW5pbm8iLCAiTWFzY3VsaW5vIikpKSAlPiUgDQogIGdyb3VwX2J5KGdlbmVybykgJT4lIA0KICBzdW1tYXJpc2UgKG4gPSBuKCkpICU+JSANCiAgbXV0YXRlKGZyZXEgPSBuL3N1bShuKSkgJT4lIA0KICBhcnJhbmdlKC1uKQ0KDQojIENvbXB1dGUgdGhlIGN1bXVsYXRpdmUgcGVyY2VudGFnZXMgKHRvcCBvZiBlYWNoIHJlY3RhbmdsZSkNCmRpdiR5bWF4IDwtIGN1bXN1bShkaXYkZnJlcSkNCg0KIyBDb21wdXRlIHRoZSBib3R0b20gb2YgZWFjaCByZWN0YW5nbGUNCmRpdiR5bWluIDwtIGMoMCwgaGVhZChkaXYkeW1heCwgbj0tMSkpDQoNCiMgQ29tcHV0ZSBsYWJlbCBwb3NpdGlvbg0KZGl2JGxhYmVsUG9zaXRpb24gPC0gKGRpdiR5bWF4ICsgZGl2JHltaW4pIC8gMg0KDQojIENvbXB1dGUgYSBnb29kIGxhYmVsDQpkaXYkbGFiZWwgPC0gcGFzdGUwKGRpdiRnZW5lcm8sICJcbiBDYW50OiAiLCBkaXYkbikNCg0KIyBNYWtlIHRoZSBwbG90DQpnZ3Bsb3QoZGl2LCBhZXMoeW1heD15bWF4LCB5bWluPXltaW4sIHhtYXg9NCwgeG1pbj0zLCBmaWxsPWdlbmVybykpICsNCiAgZ2VvbV9yZWN0KCkgKw0KICBjb29yZF9wb2xhcih0aGV0YT0ieSIpICsgIyBUcnkgdG8gcmVtb3ZlIHRoYXQgdG8gdW5kZXJzdGFuZCBob3cgdGhlIGNoYXJ0IGlzIGJ1aWx0IGluaXRpYWxseQ0KICB4bGltKGMoMiwgNCkpICsjIFRyeSB0byByZW1vdmUgdGhhdCB0byBzZWUgaG93IHRvIG1ha2UgYSBwaWUgY2hhcnQNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzg2MjRGNSIsICAiIzFGQzNBQSIsICIjRkZEMTI5IiwiIzc1ODM4RiIpKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIlJvYm90byIpKSArDQogIGxhYnModGl0bGUgPSAiR8OpbmVybyIsDQogICAgICAgZmlsbCA9ICJHw6luZXJvIiwgDQogICAgICAgY2FwdGlvbiA9IGZ1ZW50ZSkNCmBgYA0KDQoNCg0KDQojIyMgUHVlc3RvDQoNCmBgYHtyfQ0KDQpkMTwtIGQxICU+JSANCiBtdXRhdGUocHVlc3RvID0gZmN0X2NvbGxhcHNlKHB1ZXN0bywgICJWZW5kZWRvciI9IlNhbGVzIEV4ZWN1dGl2ZSIgLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSW52ZXN0aWdhZG9yIj0iUmVzZWFyY2ggU2NpZW50aXN0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGVjX2xhYm9yYXRvcmlvIj0iTGFib3JhdG9yeSBUZWNobmljaWFuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGlyX09wZXJhdGl2byI9Ik1hbnVmYWN0dXJpbmcgRGlyZWN0b3IiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBdGVuY2lvbl9jbGllbnRlIj0iSGVhbHRoY2FyZSBSZXByZXNlbnRhdGl2ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdlcmVudGUiPSJNYW5lZGFkciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNvbWVyY2lhbCI9IlNhbGVzIFJlcHJlc2VudGF0aXZlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGlyZWN0b3IiPSJSZXNlYXJjaCBEaXJlY3RvciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkhSIj0iSHVtYW4gUmVzb3VyY2VzIikpDQoNCmQxJT4lDQogIHNlbGVjdChwdWVzdG8pJT4lDQogIGdyb3VwX2J5KHB1ZXN0byklPiUNCiAgbXV0YXRlKGN1ZW50YSA9IDEpICU+JSANCiAgc3VtbWFyaXNlKEN1ZW50YSA9IHN1bShjdWVudGEpKSAlPiUgDQogIGFycmFuZ2UoLUN1ZW50YSklPiUNCiAga2FibGUoImh0bWwiLCBlc2NhcGU9RikgJT4lIA0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBUUlVFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCJob3ZlciIsImNvbmRlbnNlZCIgKSkgJT4lIA0KICByb3dfc3BlYygwLCBib2xkPVQsIGNvbG9yPSJ3aGl0ZSIsIGJhY2tncm91bmQgPSBhenVsKSAlPiUgDQogIGZvb3Rub3RlKGdlbmVyYWwgPSBmdWVudGUpDQpgYGANCg0KDQoNCiMjIyBFc3RhZG8gY2l2aWwNCg0KDQoNCmBgYHtyfQ0KDQoNCmQxPC0gZDEgJT4lIA0KIG11dGF0ZShlc3RfY2l2aWwgPSBmY3RfY29sbGFwc2UoZXN0X2NpdmlsLCAgIkNhc2FkeCI9Ik1hcnJpZWQiICwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU29sdGVyeCI9IlNpbmdsZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRpdm9yY2lhZHgiPSAiRGl2b3JjZWQiKSkNCg0KZDElPiUNCiAgc2VsZWN0KGVzdF9jaXZpbCklPiUNCiAgZ3JvdXBfYnkoZXN0X2NpdmlsKSU+JQ0KICBtdXRhdGUoY3VlbnRhID0gMSkgJT4lIA0KICBzdW1tYXJpc2UoQ3VlbnRhID0gc3VtKGN1ZW50YSkpICU+JSANCiAgYXJyYW5nZSgtQ3VlbnRhKSU+JQ0KICBrYWJsZSgiaHRtbCIsIGVzY2FwZT1GKSAlPiUgDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IFRSVUUsIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsImhvdmVyIiwiY29uZGVuc2VkIiApKSAlPiUgDQogIHJvd19zcGVjKDAsIGJvbGQ9VCwgY29sb3I9IndoaXRlIiwgYmFja2dyb3VuZCA9IGF6dWwpICU+JSANCiAgZm9vdG5vdGUoZ2VuZXJhbCA9IGZ1ZW50ZSkNCg0KDQpgYGANCg0KIyMjIEVkYWQNCg0KQXJtYW1vcyBncnVwb3MgZGUgZWRhZA0KDQpQcmltZXJvIGNvbnN1bHRhbW9zIGxhcyBlZGFkZXMgcGFyYSBhcm1hciBsYXMgY2F0ZWdvcsOtYXM6DQoNCmBgYHtyfQ0KDQpkMSU+JQ0KICBzZWxlY3QoZWRhZCklPiUNCiAgZ3JvdXBfYnkoZWRhZCklPiUNCiAgbXV0YXRlKGN1ZW50YSA9IDEpICU+JSANCiAgc3VtbWFyaXNlKEN1ZW50YSA9IHN1bShjdWVudGEpKSAlPiUgDQogIGFycmFuZ2UoLUN1ZW50YSkNCg0KDQpgYGANCg0KRW4gZnVuY2nDs24gZGUgbGFzIGNhbnRpZGFkZXMgcHJldmlhcywgYXJtYW1vcyBsYXMgY2F0ZWdvcsOtYXMgYWRlY3VhZGFzOiANCg0KYGBge3J9DQoNCmQxPC1kMSU+JSANCiAgICAgICAgIG11dGF0ZShlZGFkX2NhdCA9IGNhc2Vfd2hlbigNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWRhZCA+IDE3ICYgZWRhZCA8PSAyNSB+ICIxOC0yNSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVkYWQgPiAyNSAmIGVkYWQgPD0gMzUgfiAiMjYtMzUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZGFkID4gMzUgJiBlZGFkIDw9IDQ2IH4gIjM2LTQ1IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWRhZCA+IDQ1ICYgZWRhZCA8PSA1MCB+ICI0Ni01MCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVkYWQgPiA1MCAmIGVkYWQgPD0gNjQgfiAiNTEtNjQiLCAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVkYWQgPiA2NCAgICAgICAgICAgICB+ICI+IDY0Ig0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSAlPiUgDQogICAgICAgICBtdXRhdGUoZWRhZF9jYXQgPSBmYWN0b3IoZWRhZF9jYXQsDQogICAgICAgICBsZXZlbCA9IGMoIjE4LTI1IiwiMjYtMzUiLCAiMzYtNDUiLCI0Ni01MCIsIjUxLTY0IiwiPiA2NCIpDQogICAgKSkgDQoNCg0KZDElPiUNCiAgc2VsZWN0KGVkYWRfY2F0KSU+JQ0KICBncm91cF9ieShlZGFkX2NhdCklPiUNCiAgbXV0YXRlKGN1ZW50YSA9IDEpICU+JSANCiAgc3VtbWFyaXNlKEN1ZW50YSA9IHN1bShjdWVudGEpKSAlPiUgDQogIGFycmFuZ2UoLUN1ZW50YSklPiUNCiAga2FibGUoImh0bWwiLCBlc2NhcGU9RikgJT4lIA0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBUUlVFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCJob3ZlciIsImNvbmRlbnNlZCIgKSkgJT4lIA0KICByb3dfc3BlYygwLCBib2xkPVQsIGNvbG9yPSJ3aGl0ZSIsIGJhY2tncm91bmQgPSBhenVsKSAlPiUgDQogIGZvb3Rub3RlKGdlbmVyYWwgPSBmdWVudGUpDQoNCg0KYGBgDQoNCiMjIyBFc3BlY2lhbGlkYWQNCg0KDQpgYGB7cn0NCmQxJT4lDQogIHNlbGVjdChlc3BlY2lhbGlkYWQpJT4lDQogIGdyb3VwX2J5KGVzcGVjaWFsaWRhZCklPiUNCiAgbXV0YXRlKGN1ZW50YSA9IDEpICU+JSANCiAgc3VtbWFyaXNlKEN1ZW50YSA9IHN1bShjdWVudGEpKSAlPiUgDQogIGFycmFuZ2UoLUN1ZW50YSkNCg0KDQpkMTwtIGQxICU+JSANCiBtdXRhdGUoZXNwZWNpYWxpZGFkID0gZmN0X2NvbGxhcHNlKGVzcGVjaWFsaWRhZCwgICJDaWVuY2lhcyI9IkxpZmUgU2NpZW5jZXMiICwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWVkaWNpbmEiPSJNZWRpY2FsIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWt0Ij0iTWFya2V0aW5nIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSFIiPSJIdW1hbiBSZXNvdXJjZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90cm9zIj0iT3RoZXIiDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkNCg0KYGBgDQoNCg0KIyMgUmVsYWNpb25lcw0KDQoNCkVtcGVjZW1vcyB2aWVuZG8gbGEgcmVwcmVzZW50YWNpw7NuIHBvcmNlbnR1YWwgZGUgcm90YWNpw7NuLiANCg0KUG9kZW1vcyB2aXN1YWxpemFybG8gZW4gdW5hIHRhYmxhOiANCg0KDQpgYGB7cn0NCg0KZDElPiUNCiAgc2VsZWN0KHJvdGFjaW9uKSU+JQ0KICBncm91cF9ieShyb3RhY2lvbiklPiUNCiAgcmVuYW1lKCJSb3RhY2nDs24iPSJyb3RhY2lvbiIpICU+JSANCiAgbXV0YXRlKGN1ZW50YSA9IDEpICU+JSANCiAgc3VtbWFyaXNlKENhbnRpZGFkID0gc3VtKGN1ZW50YSkpICU+JSANCiAgYXJyYW5nZSgtQ2FudGlkYWQpICU+JSANCiAgbXV0YXRlKFBvcmNlbnRhamUgPSByb3VuZChwcm9wLnRhYmxlKENhbnRpZGFkKSwgMikpICU+JSANCiAga2FibGUoImh0bWwiLCBlc2NhcGU9RikgJT4lIA0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBUUlVFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCJob3ZlciIsImNvbmRlbnNlZCIgKSkgJT4lIA0KICByb3dfc3BlYygwLCBib2xkPVQsIGNvbG9yPSJ3aGl0ZSIsIGJhY2tncm91bmQgPSBhenVsKSAlPiUgDQogIGZvb3Rub3RlKGdlbmVyYWwgPSBmdWVudGUpDQoNCg0KDQpgYGANCg0KRW4gdW4gcGllIGNoYXJ0LCB5YSBzZWEgaW5jbHV5ZW5kbyBjYW50aWRhZGVzIG8gc29sbyB1bmEgcmVmZXJlbmNpYSB2aXN1YWw6IA0KDQoNCmBgYHtyfQ0KZzc8LWQxJT4lIA0KICBzZWxlY3Qocm90YWNpb24pJT4lDQogIGdyb3VwX2J5KHJvdGFjaW9uKSU+JQ0KICBzdW1tYXJpc2UoY291bnRzID0gbigpKSAlPiUNCiAgbXV0YXRlKHByb3AgPSAoY291bnRzIC8gc3VtKGNvdW50cykpICogMTAwKSAlPiUNCiAgYXJyYW5nZShkZXNjKHByb3ApKSAlPiUgDQpnZ3Bsb3QoYWVzKCIiLCBjb3VudHMpKSArDQogIGdlb21fY29sKA0KICAgIHBvc2l0aW9uID0gImZpbGwiLA0KICAgIGNvbG9yID0gImJsYWNrIiwNCiAgICB3aWR0aCA9IDEsDQogICAgYWVzKGZpbGwgPSBmYWN0b3Iocm90YWNpb24pKQ0KICApICsNCiAgZ2VvbV90ZXh0KA0KICAgIGFlcyhsYWJlbCA9IHN0cl9jKHJvdW5kKHByb3ApLCAiJSIpLCBncm91cCA9IGZhY3Rvcihyb3RhY2lvbikpLA0KICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZmlsbCh2anVzdCA9IDAuNSksDQogICAgY29sb3IgPSAid2hpdGUiLA0KICAgIHNpemUgPSA2LA0KICAgIHNob3cubGVnZW5kID0gRkFMU0UsDQogICAgZm9udGZhY2UgPSAiYm9sZCINCiAgKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsICh2YWx1ZXMgPSBjKGF6dWwsdmVyZGUpKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUm90YWNpw7NuICIsDQogICAgc3VidGl0bGUgPSAiIiwNCiAgICBjYXB0aW9uID0gIiIsDQogICAgZmlsbCA9ICIiDQogICkNCg0KYGBgDQoNCg0KYGBge3J9DQoNCg0KZzg8LWQxJT4lIA0KICBzZWxlY3Qocm90YWNpb24pJT4lDQogIGdyb3VwX2J5KHJvdGFjaW9uKSU+JQ0KICBzdW1tYXJpc2UoY291bnRzID0gbigpKSAlPiUNCiAgbXV0YXRlKHByb3AgPSAoY291bnRzIC8gc3VtKGNvdW50cykpICogMTAwKSAlPiUNCiAgYXJyYW5nZShkZXNjKHByb3ApKQ0KDQpnODwtZ2dwbG90KGc4LCBhZXMoeD0iIiwgeT1wcm9wLCBmaWxsPXJvdGFjaW9uKSkgKw0KICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHdpZHRoPTEsIGNvbG9yPSJ3aGl0ZSIpICsNCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydD0wKSArDQogIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3RhY2lvbiksIGNvbG9yID0gIndoaXRlIiwgc2l6ZT02KSsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iU2V0MiIpDQoNCg0KDQoNCmBgYA0KDQoNCmBgYHtyfQ0KZzcNCmc4DQpgYGANCg0KDQojIyMgRXNwZWNpYWxpZGFkICAmIFJvdGFjacOzbiANCg0KDQpBaG9yYSByZWxhY2lvbmVtb3MgbGEgZXNwZWNpYWxpZGFkICBjb24gbGEgcm90YWNpw7NuLg0KDQoNCmBgYHtyfQ0KDQpkMSU+JSANCiAgcmVuYW1lKA0KICBFc3BlY2lhbGlkYWQ9ICAiZXNwZWNpYWxpZGFkIiklPiUNCiAgcGxvdF9seSh4ID0gfkVzcGVjaWFsaWRhZCwgY29sb3IgID1+cm90YWNpb24sIGNvbG9ycyA9ICJBY2NlbnQiICklPiUNCiAgbGF5b3V0KHlheGlzID0gbGlzdCh0aXRsZSA9ICdDYW50aWRhZCcpKQ0KDQpgYGANCg0KDQoNCiMjIyBHZW5lcm8gJiBFc3BlY2lhbGlkYWQgDQoNCkRlIGxvcyBxdWUgc2UgZnVlcm9uLCBwb2RlbW9zIG9ic2VydmFyIGxhIHJlbGFjacOzbiBlbnRyZSBnw6luZXJvIHkgY2FtcG8gZGUgZXNwZWNpYWxpZGFkDQoNCmBgYHtyfQ0KDQpnMTwtDQogIGQxICU+JSANCiAgICBzZWxlY3Qocm90YWNpb24sZ2VuZXJvLGVzcGVjaWFsaWRhZCkgJT4lDQogICAgcmVuYW1lKCJHw6luZXJvIj1nZW5lcm8pICU+JSANCiAgICBmaWx0ZXIgKHJvdGFjaW9uPT0iU2kiKSAlPiUNCiAgICBncm91cF9ieShlc3BlY2lhbGlkYWQsR8OpbmVybykgJT4lIA0KICAgIHN1bW1hcmlzZShDYW50aWRhZD1uKCkpIA0KDQogIGdncGxvdChkYXRhPWcxLGFlcyh4PWVzcGVjaWFsaWRhZCx5ID0gQ2FudGlkYWQgLGZpbGw9R8OpbmVybykpKw0KICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoKSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoYXp1bCwgdmVyZGUpKSArDQogICAgZ2d0aXRsZSgiRXNwZWNpYWxpZGFkICYgR2VuZXJvICIpKw0KICBsYWJzKHggPSAiIiwgeSA9ICIiKQ0KICANCiAgDQogIA0KYGBgDQoNCiMjIyBJbmdyZXNvcyB2cyBSb3RhY2nDs24NCg0KVmVhbW9zIGxhIHJlbGFjacOzbiBlbnRyZSBpbmdyZXNvcyB5IHJvdGFjacOzbi4NCg0KTWVkaWFudGUgbGEgc2lndWllbnRlIHRhYmxhIGFuYWxpemFtb3MgbG9zIHZhbG9yZXMgZXN0YW5kYXIuDQoNCmBgYHtyfQ0KDQpkMSU+JSANCiAgc3VtbWFyaXNlKE1lZGlhbmEgPSBtZWRpYW4oc3VlbGRvKSwgDQogICAgICAgICAgICAgIFByb21lZGlvID0gbWVhbihzdWVsZG8pLA0KICAgICAgICAgICAgICBNYXggPSBtYXgoc3VlbGRvKSwgDQogICAgICAgICAgICAgIE1pbiA9IG1pbihzdWVsZG8pKSAlPiUgDQogIGthYmxlKCJodG1sIiwgZXNjYXBlPUYpICU+JSANCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gVFJVRSwgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwiaG92ZXIiLCJjb25kZW5zZWQiICkpICU+JSANCiAgcm93X3NwZWMoMCwgYm9sZD1ULCBjb2xvcj0id2hpdGUiLCBiYWNrZ3JvdW5kID0gYXp1bCkNCmBgYA0KDQpOb3MgaW50ZXJlc2EgcmVsYWNpb25hciBnZW5lcm8sIGluZ3Jlc29zIHkgcm90YWNpb24uIA0KDQpDb21vIHZlbW9zIGVuIGVsIHNpZ3VpZW50ZSBncmFmaWNvLCBxdWllbmVzIHNlIGZ1ZXJvbiBkZSBsYSBlbXByZXNhLCBlcyBzaW1pbGFyIGVsIHN1ZWxkbywgYWwgaWd1YWwgcXVlIGxhIGNhbnRpZGFkIGRlIHBlcnNvbmFzLiBMYSBtYXlvcmlhIGRlIGxvcyBvdXRsaWVycyBzZSBwcmVzZW50YSBlbiBlbCBnw6luZXJvIG1hc2N1bGluby4gDQoNCkRlIGxvcyBxdWUgIHNlIGVuY3VlbnRyYW4gYWN0aXZvcywgbG9zIHN1ZWxkb3MgbcOhcyBhbHRvcyBsb3MgdGllbmVuIGxhcyBtdWplcmVzLiANCg0KYGBge3J9DQoNCmdncGxvdChkMSwgYWVzKHg9cm90YWNpb24sIHk9c3VlbGRvLCBjb2xvcj1nZW5lcm8sIGZpbGw9Z2VuZXJvKSkgKw0KICAgIGdlb21fYm94cGxvdCgpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KDQpnMjwtZDElPiUgDQogIGZpbHRlcihyb3RhY2lvbj09IlNpIiklPiUNCiAgcGxvdF9seSh4ID0gfmRlcGFydGFtZW50bywgY29sb3IgID1+Z2VuZXJvLCBjb2xvcnMgPSAiQWNjZW50IiApJT4lDQogIGxheW91dCh5YXhpcyA9IGxpc3QodGl0bGUgPSAnQ2FudGlkYWQnKSkNCg0KZzM8LWQxJT4lIA0KICBmaWx0ZXIocm90YWNpb249PSJObyIpJT4lDQogIHBsb3RfbHkoeCA9IH5kZXBhcnRhbWVudG8sIGNvbG9yICA9fmdlbmVybywgY29sb3JzID0gIkFjY2VudCIgKSU+JQ0KICBsYXlvdXQoeWF4aXMgPSBsaXN0KHRpdGxlID0gJ0NhbnRpZGFkJykpDQoNCmcyDQpnMw0KYGBgDQoNCsK/SGF5IGFsZ3VuYSByZWxhY2lvbiBlbnRyZSBsYXMgcGVyc29uYXMgcXVlIHNlIGZ1ZXJvbiB5IGxvcyBxdWUgaGljaWVyb24gaG9yYXMgZXh0cmFzPw0KDQoNClByaW1lcm8gdmVhbW9zIHVuIGN1YWRybyBnZW5lcmFsIGVudHJlIEdlbmVybywgaG9yYXMgZXh0cmFzIHkgc3VlbGRvLg0KDQpWZW1vcyBxdWUgbGFzIG11amVyZXMgY29uIHN1ZWxkbyBtYXMgYWx0bywgc29uIHF1aWVuZXMgaGFjZW4gaG9yYXMgZXh0cmFzLCBlbiBjYW1iaW8gZW50cmUgbG9zIGhvbWJyZXMsIGhhZ2FuIG8gbm8gaG9yYXMgZXh0cmFzIGVsIHN1ZWxkbyBlcyBzaW1pbGFyLiANCg0KYGBge3J9DQoNCmc2PC1nZ3Bsb3QoZDEsIGFlcyh4PWhzX2V4dHJhcywgeT1zdWVsZG8sIGNvbG9yPWdlbmVybywgZmlsbD1nZW5lcm8pKSArDQogICAgZ2VvbV9ib3hwbG90KCkNCg0KZzYNCg0KYGBgDQoNClZlYW1vcyBhaG9yYSBjb21vIGltcGFjdGEgbGFzIGhvcmFzIGV4dHJhcyBleHRyZSBsYXMgcGVyc29uYXMgcXVlIHNlIHZhbiBkZSBsYSBjb21wYcOxaWE6IA0KYGBge3J9DQoNCmc0PC1kMSAlPiUgDQogIHNlbGVjdChoc19leHRyYXMsIHN1ZWxkbywgZ2VuZXJvLCByb3RhY2lvbikgJT4lIA0KICBmaWx0ZXIocm90YWNpb249PSJTaSIpICU+JSANCiAgZ2dwbG90KCBhZXMoeD1oc19leHRyYXMsIHk9c3VlbGRvLCBjb2xvcj1nZW5lcm8sIGZpbGw9Z2VuZXJvKSkgKw0KICAgIGdlb21fYm94cGxvdCgpKw0KICAgIGxhYnModGl0bGU9J0JhamFzJykNCg0KDQpnNTwtZDEgJT4lIA0KICBzZWxlY3QoaHNfZXh0cmFzLCBzdWVsZG8sIGdlbmVybywgcm90YWNpb24pICU+JSANCiAgZmlsdGVyKHJvdGFjaW9uPT0iTm8iKSAlPiUgDQogIGdncGxvdCggYWVzKHg9aHNfZXh0cmFzLCB5PXN1ZWxkbywgY29sb3I9Z2VuZXJvLCBmaWxsPWdlbmVybykpICsNCiAgICBnZW9tX2JveHBsb3QoKSsNCiAgIGxhYnModGl0bGU9J0FjdGl2b3MnKQ0KDQpnNA0KZzUNCg0KYGBgDQoNCg0KUG9kZW1vcyBvYnNlcnZhciBxdWUgbG9zIHN1ZWxkb3MgcHJvbWVkaW8gZGUgcXVpZW5lcyBzZSB2YW4gZGUgbGEgY29tcGHDsWlhIG5vIHRpZW5lbiBkaWZlcmVuY2lhcyBwb3IgZ2VuZXJvLiANCg0KYGBge3J9DQoNCiBkMSAlPiUgDQogIHNlbGVjdChwdWVzdG8sIHN1ZWxkbywgZ2VuZXJvLHJvdGFjaW9uKSAlPiUgDQogIGZpbHRlcihyb3RhY2lvbj09IlNpIikgJT4lIA0KICBncm91cF9ieShnZW5lcm8pICU+JSANCiAgc3VtbWFyaXNlKG1lZGlhX3NhbGFyaWFsID0gbWVhbihzdWVsZG8pKSAlPiUgDQogIGthYmxlKCJodG1sIiwgZXNjYXBlPUYpICU+JSANCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gVFJVRSwgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwiaG92ZXIiLCJjb25kZW5zZWQiICkpICU+JSANCiAgcm93X3NwZWMoMCwgYm9sZD1ULCBjb2xvcj0id2hpdGUiLCBiYWNrZ3JvdW5kID0gYXp1bCkgJT4lIA0KICBmb290bm90ZShnZW5lcmFsID0gZnVlbnRlKQ0KYGBgDQoNCg0KYGBge3J9DQoNCiMjIFNvbG8gc2UgcmVwcm9kdWNlIGVuIGVsIGRhc2hib2FyZCANCiNicmVjaGEgPC0gZDEgJT4lIA0KIyAgc2VsZWN0KHB1ZXN0bywgc3VlbGRvLCBnZW5lcm8scm90YWNpb24pICU+JSANCiMgIGZpbHRlcihyb3RhY2lvbj09IlNpIikgJT4lIA0KIyAgZ3JvdXBfYnkoZ2VuZXJvKSAlPiUgDQojICBzdW1tYXJpc2UobWVkaWFfc2FsYXJpYWwgPSBtZWFuKHN1ZWxkbykpDQoNCiNicmVjaGFfZ3JhZiA8LSBicmVjaGEgJT4lIA0KIyAgcGl2b3Rfd2lkZXIoLiwgbmFtZXNfZnJvbSA9IGdlbmVybywgdmFsdWVzX2Zyb20gPSBtZWRpYV9zYWxhcmlhbCkgJT4lIA0KIyAgbXV0YXRlKGJyZWNoYSA9IHBlcmNlbnQoKE1hc2N1bGluby1GZW1lbmlubykvTWFzY3VsaW5vLCAxKSwNCiMgICAgICAgICB4ID0gKE1hc2N1bGlubyArIEZlbWVuaW5vKS8yLA0KIyAgICAgICAgIGdhcCA9IEZlbWVuaW5vL01hc2N1bGlubykNCg0KIyBDYWxjdWxhciBlbCBpbmRpY2Fkb3IgZGUgYnJlY2hhIHNhbGFyaWFsIA0KI2JyZWNoYV9wcm9tZWRpbyA8LSByb3VuZChtZWFuKGJyZWNoYV9ncmFmJGdhcCoxMDApKQ0KDQojIyMgU3VlbGRvIFByb21lZGlvIE11amVyZXMNCg0KIyhyb3VuZChtZWFuKGJyZWNoYV9ncmFmJEZlbWVuaW5vKSksIGljb24gPSAiZmEtZmVtYWxlIiwgY29sb3IgPSAiIzg2MjRGNSIpDQoNCiMjIyBTdWVsZG8gUHJvbWVkaW8gSG9tYnJlcw0KI3ZhbHVlQm94KHJvdW5kKG1lYW4oYnJlY2hhX2dyYWYkTWFzY3VsaW5vKSksIGljb24gPSAiZmEtbWFsZSIsIGNvbG9yID0gIiMxRkMzQUEiKQ0KDQpgYGANCg0KWSBzaSBiaWVuLCBsb3Mgc3VlbGRvcyBwcm9tZWRpb3Mgc29uIGNhc2kgaWRlbnRpY29zLCBvYnNlcnZhbW9zIHF1ZSBsYSBjYW50aWRhZCBkZSBwZXJzb25hcyBubyBhY3RpdmFzIGRlIGNhZGEgZ2VuZXJvIHZhcmlhIGVuIGZvcm1hIGNvbnNpZGVyYWJsZS4gDQpgYGB7cn0NCmQxICU+JSANCiAgICBzZWxlY3Qocm90YWNpb24sZ2VuZXJvKSAlPiUNCiAgICBmaWx0ZXIgKHJvdGFjaW9uPT0iU2kiKSAlPiUNCiAgICBncm91cF9ieShnZW5lcm8pICU+JSANCiAgICBzdW1tYXJpc2UoQ2FudGlkYWQ9bigpKSANCg0KDQoNCg0KYGBgDQoNClBvZGVtb3Mgb2JzZXJ2YXIgbGEgbWlzbWEgaW5mb3JtYWNpw7NuIGNvbiBsYSBzaWd1aWVudGUgdmlzdWFsaXphY2nDs24NCg0KDQpgYGB7cn0NCg0KZDElPiUgDQogIGZpbHRlcihyb3RhY2lvbj09IlNpIikgJT4lIA0KICByZW5hbWUoIEfDqW5lcm89ICAiZ2VuZXJvIiklPiUNCiAgcGxvdF9seSh4ID0gfkfDqW5lcm8sIGNvbG9yICA9fnJvdGFjaW9uLCBjb2xvcnMgPSAiQWNjZW50IiApJT4lDQogIGxheW91dCh5YXhpcyA9IGxpc3QodGl0bGUgPSAnQ2FudGlkYWQnKSkNCg0KYGBgDQoNCg0K